package com.xusl.spring.factory;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @Author: xusl
 * @Date: 2021/8/3 10:57 下午
 */
@Slf4j
public class BeanFactory {

    private static Map<String, Object> MAP = new HashMap<>();

    static {
        // 加载xml配置文件到字节流
        InputStream is = BeanFactory.class.getClassLoader().getResourceAsStream("beans.xml");

        // 解析字节流到MAP中
        SAXReader saxReader = new SAXReader();
        try {
            Document document = saxReader.read(is);
            Element rootElement = document.getRootElement();

            List<Element> beanElements = rootElement.selectNodes("//bean");
            if (CollectionUtils.isNotEmpty(beanElements)) {
                for (Element element : beanElements) {
                    String id = element.attributeValue("id");
                    String clazz = element.attributeValue("class");

                    // 通过反射实例化bean
                    Class<?> beanClazz = Class.forName(clazz);
                    Object bean = beanClazz.newInstance();

                    MAP.put(id, bean);
                }
            }

            // 给bean属性赋值

            // 获取所有的property标签元素
            List<Element> propertyList = rootElement.selectNodes("//property");
            if (CollectionUtils.isNotEmpty(propertyList)) {
                for (Element element : propertyList) {
                    // 获取name和ref值
                    String name = element.attributeValue("name");
                    String ref = element.attributeValue("ref");
                    // 找到父元素
                    Element parent = element.getParent();
                    String parentId = parent.attributeValue("id");

                    // 通过反射给父元素属性赋值
                    Object parentBean = MAP.get(parentId);
                    Method[] methods = parentBean.getClass().getDeclaredMethods();
                    if (ArrayUtils.isNotEmpty(methods)) {
                        for (Method method : methods) {
                            if (method.getName().equalsIgnoreCase("set" + name)) {
                                method.invoke(parentBean, MAP.get(ref));
                            }
                        }
                    }

                    // 把父元素重新放到map容器中
                    MAP.put(parentId, parentBean);
                }
            }

        } catch (Throwable throwable) {
            log.error("error", throwable);
        }
    }

    public static Object getBean(String id) {
        return MAP.get(id);
    }
}
